Popular Searches
Popular Course Categories
Popular Courses

Creating and Using Abstract Classes

Creating and Using Abstract Classes

Abstraction, Interfaces, and Object Relationships

Creating and Using Abstract Classes in Java

Course: Core Java Training

Topic: Creating and Using Abstract Classes

Course URL: Core Java Training Course

Demo URL: Register for a Course Demo

Website: JustAcademy Official Website


1. Introduction to Abstract Classes

Abstract classes are an important concept in Java object-oriented programming. They allow developers to define a common structure for related classes while leaving certain behaviors for individual subclasses to implement.

For example, a banking application may support savings accounts, current accounts, and fixed deposit accounts. All these accounts share common information, such as account number and account holder name. However, their interest calculations or transaction rules may differ.

Instead of duplicating common fields and methods in every account class, developers can create an abstract class named BankAccount. This class can contain shared functionality and declare abstract methods for operations that depend on the specific account type.

Abstract classes support abstraction, inheritance, code reuse, and runtime polymorphism. They are useful when several related classes share common characteristics but require different implementations for particular operations.

2. Learning Objectives

After studying this topic, you will be able to:

  • Understand the purpose of abstract classes in Java.
  • Declare abstract classes using the abstract keyword.
  • Create abstract methods and concrete methods.
  • Extend abstract classes using inheritance.
  • Implement abstract methods in concrete subclasses.
  • Use constructors and instance variables in abstract classes.
  • Understand abstract class references and runtime polymorphism.
  • Compare abstract classes with interfaces.
  • Identify common compilation errors and apply best practices.

3. What Is an Abstract Class?

An abstract class is a class declared using the abstract keyword. It represents a general or incomplete concept that cannot be instantiated directly.

An abstract class can contain abstract methods without implementations and concrete methods with implementations. It can also contain instance variables, constructors, static methods, and other regular class members.

Syntax

abstract class ClassName {
    // Instance variables

    // Constructor

    abstract void abstractMethod();

    void concreteMethod() {
        System.out.println("This is a concrete method");
    }
}

In this example:

  • abstract declares the class as abstract.
  • abstractMethod() declares a method without a method body.
  • concreteMethod() provides a complete implementation.

An abstract class cannot be instantiated directly with the new keyword. Instead, it is normally extended by subclasses that provide any required missing implementations.

4. Understanding the abstract Keyword

The abstract keyword indicates that a class or method is intended to be extended or implemented by a subclass.

4.1 Abstract Class

abstract class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
}

This is a valid abstract class even though it does not contain an abstract method. A class may be declared abstract simply to prevent direct instantiation and establish a common parent for subclasses.

4.2 Abstract Method

abstract class Animal {
    abstract void makeSound();
}

The method makeSound() has no body and ends with a semicolon. It specifies behavior that a concrete subclass must implement.

If a class declares an abstract method, the class itself must be declared abstract.

5. Difference Between Abstract and Concrete Classes

Feature Abstract Class Concrete Class
Declaration Uses the abstract keyword. Does not use the abstract keyword.
Instantiation Cannot be instantiated directly. Can be instantiated if it has an accessible constructor.
Abstract methods May contain abstract methods. Cannot declare its own abstract methods.
Concrete methods Can contain implemented methods. Can contain implemented methods.
Constructors Can contain constructors. Can contain constructors.
Purpose Provides a shared, potentially incomplete foundation. Provides a complete implementation that can be instantiated.
Inheritance Can be extended by abstract or concrete classes. Can also be extended by subclasses.

6. Creating Your First Abstract Class

Let's create an abstract class named Animal and a concrete subclass named Dog. The parent class defines a general behavior, while the subclass determines the actual implementation.

Java Program

abstract class Animal {
    abstract void makeSound();
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.makeSound();
    }
}

Output

Dog barks

Explanation

  • Animal is declared as an abstract class.
  • makeSound() is an abstract method without a body.
  • Dog inherits from Animal using extends.
  • The Dog class implements the abstract method.
  • The program creates a Dog object and invokes its method.

This example demonstrates how an abstract class establishes a common requirement while allowing subclasses to provide their own behavior.

7. Abstract Classes with Abstract and Concrete Methods

An abstract class can contain both abstract and concrete methods. This allows subclasses to reuse common functionality while implementing the behavior that differs between them.

Java Program

abstract class Vehicle {
    String brand;

    Vehicle(String brand) {
        this.brand = brand;
    }

    void displayBrand() {
        System.out.println("Brand: " + brand);
    }

    abstract void start();
}

class Car extends Vehicle {
    Car(String brand) {
        super(brand);
    }

    @Override
    void start() {
        System.out.println("Car starts with a key or button");
    }
}

class Motorcycle extends Vehicle {
    Motorcycle(String brand) {
        super(brand);
    }

    @Override
    void start() {
        System.out.println("Motorcycle starts using its starting system");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car("Toyota");
        Motorcycle motorcycle = new Motorcycle("Honda");

        car.displayBrand();
        car.start();

        motorcycle.displayBrand();
        motorcycle.start();
    }
}

Output

Brand: Toyota
Car starts with a key or button
Brand: Honda
Motorcycle starts using its starting system

Explanation

The abstract class Vehicle contains a field named brand, a constructor, a concrete method named displayBrand(), and an abstract method named start().

The Car and Motorcycle classes inherit the shared brand-related functionality. Each class implements start() according to its own requirements.

The super(brand) statement invokes the constructor of the abstract parent class to initialize the inherited state. The abstract class constructor executes as part of creating a subclass object.

8. Rules for Abstract Classes in Java

  • An abstract class must be declared with the abstract keyword.
  • An abstract class cannot be instantiated directly.
  • An abstract class may contain zero or more abstract methods.
  • A class declaring an abstract method must itself be abstract.
  • A concrete subclass must implement all inherited abstract methods that remain unimplemented.
  • If a subclass leaves any required abstract methods unimplemented, it must also be declared abstract.
  • An abstract class can contain constructors, fields, static methods, and concrete methods.
  • An abstract class can extend another class and implement one or more interfaces.
  • A Java class can extend only one direct superclass.
  • An abstract method cannot be declared private, static, or final.
  • An abstract method has no method body.
  • A final class cannot be extended and therefore cannot be declared abstract at the same time.

9. Implementing Multiple Abstract Methods

An abstract class can declare multiple abstract methods when subclasses must provide several specific behaviors.

Java Program

abstract class Shape {
    abstract double calculateArea();
    abstract double calculatePerimeter();

    void describe() {
        System.out.println("This is a geometric shape");
    }
}

class Rectangle extends Shape {
    double length;
    double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    double calculateArea() {
        return length * width;
    }

    @Override
    double calculatePerimeter() {
        return 2 * (length + width);
    }
}

public class Main {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(5, 3);

        rectangle.describe();
        System.out.println("Area: " + rectangle.calculateArea());
        System.out.println("Perimeter: " + rectangle.calculatePerimeter());
    }
}

Output

This is a geometric shape
Area: 15.0
Perimeter: 16.0

Explanation

The abstract class Shape requires subclasses to provide implementations for calculating area and perimeter. The Rectangle class implements both methods using its length and width.

The concrete method describe() is inherited and reused without being rewritten in the subclass.

10. Using Abstract Class References

Although an abstract class cannot be instantiated directly, it can be used as the declared type of a reference variable. That reference can point to an object created from a concrete subclass.

Java Program

abstract class Employee {
    abstract void calculateSalary();
}

class FullTimeEmployee extends Employee {
    @Override
    void calculateSalary() {
        System.out.println("Calculating monthly salary");
    }
}

class ContractEmployee extends Employee {
    @Override
    void calculateSalary() {
        System.out.println("Calculating contract payment");
    }
}

public class Main {
    public static void main(String[] args) {
        Employee employee1 = new FullTimeEmployee();
        Employee employee2 = new ContractEmployee();

        employee1.calculateSalary();
        employee2.calculateSalary();
    }
}

Output

Calculating monthly salary
Calculating contract payment

Here, Employee is the reference type, while the actual objects are FullTimeEmployee and ContractEmployee. Java invokes the overridden method according to the actual object's runtime class. This behavior is called runtime polymorphism.

11. Abstract Classes and Constructors

Abstract classes can have constructors to initialize common fields shared by their subclasses. These constructors are not called to instantiate the abstract class directly. Instead, they execute during the construction of a subclass object.

Java Program

abstract class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void displayDetails() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }

    abstract void performRole();
}

class Student extends Person {
    Student(String name, int age) {
        super(name, age);
    }

    @Override
    void performRole() {
        System.out.println("Role: Learning");
    }
}

public class Main {
    public static void main(String[] args) {
        Student student = new Student("Amit", 20);
        student.displayDetails();
        student.performRole();
    }
}

Output

Name: Amit
Age: 20
Role: Learning

The Person constructor initializes the common fields. The Student constructor calls it using super(name, age). The subclass implements the abstract method performRole().

12. Abstract Classes and Method Overriding

Method overriding occurs when a subclass provides its own implementation of an inherited instance method with a compatible method signature. Abstract methods are designed to be implemented by concrete subclasses.

abstract class Appliance {
    abstract void turnOn();

    void showCategory() {
        System.out.println("Home appliance");
    }
}

class Fan extends Appliance {
    @Override
    void turnOn() {
        System.out.println("Fan starts rotating");
    }
}

class WashingMachine extends Appliance {
    @Override
    void turnOn() {
        System.out.println("Washing machine starts its cycle");
    }
}

Both subclasses implement the same abstract method but provide different behaviors. They also inherit the concrete method showCategory().

The @Override annotation is recommended because it allows the compiler to detect mistakes in method signatures.

13. Abstract Classes vs. Interfaces

Abstract classes and interfaces both support abstraction, but they are used for different design purposes. Abstract classes are useful for sharing state and implementation among closely related classes. Interfaces are useful for defining capabilities that different classes can implement.

Feature Abstract Class Interface
Declaration Uses abstract class. Uses the interface keyword.
Inheritance keyword A subclass uses extends. A class uses implements.
Instance fields Can contain instance variables. Fields are implicitly public static final.
Constructors Can have constructors. Cannot have constructors.
Implemented methods Can contain concrete instance methods. Can contain default, static, and private methods subject to Java version rules.
Abstract methods Can declare abstract methods. Can declare abstract instance methods.
Inheritance limit A class can extend only one class. A class can implement multiple interfaces.
Best use Sharing common state and implementation among related classes. Defining a capability or contract for different classes.

When Should You Use an Abstract Class?

Use an abstract class when related classes share state, constructors, or implemented behavior. For example, a Vehicle class may store common registration information and provide shared methods.

When Should You Use an Interface?

Use an interface when different classes need to support the same capability. For example, an interface named Printable could be implemented by invoices, reports, and photographs.

14. Real-World Applications of Abstract Classes

  • Banking systems: A common account class can store account information while different account types implement their own rules.
  • Payment systems: A payment class can store transaction information while subclasses implement different payment methods.
  • Employee management: A base employee class can store common details while different employee types calculate compensation differently.
  • Vehicle management: A vehicle class can provide common information while cars, motorcycles, and buses implement specific operations.
  • Graphics applications: A shape class can define common properties while circles and rectangles implement their own area calculations.
  • Notification systems: A notification class can hold recipient information while email and SMS subclasses provide delivery-specific behavior.
  • File processing: A shared processor class can define common workflow steps while subclasses handle different file formats.

15. Practical Example: Payment Processing System

This example demonstrates how an abstract class can combine common payment information with different payment implementations.

Java Program

abstract class Payment {
    double amount;

    Payment(double amount) {
        this.amount = amount;
    }

    void showAmount() {
        System.out.println("Payment amount: " + amount);
    }

    abstract void processPayment();
}

class UpiPayment extends Payment {
    UpiPayment(double amount) {
        super(amount);
    }

    @Override
    void processPayment() {
        System.out.println("Processing UPI payment");
    }
}

class CardPayment extends Payment {
    CardPayment(double amount) {
        super(amount);
    }

    @Override
    void processPayment() {
        System.out.println("Processing card payment");
    }
}

public class Main {
    public static void main(String[] args) {
        Payment payment1 = new UpiPayment(1500.00);
        Payment payment2 = new CardPayment(2500.00);

        payment1.showAmount();
        payment1.processPayment();

        payment2.showAmount();
        payment2.processPayment();
    }
}

Output

Payment amount: 1500.0
Processing UPI payment
Payment amount: 2500.0
Processing card payment

Step-by-Step Explanation

  1. The abstract class Payment stores the common payment amount.
  2. The constructor initializes the amount.
  3. The concrete method showAmount() displays shared information.
  4. The abstract method processPayment() defines a behavior that subclasses must implement.
  5. The UpiPayment and CardPayment classes extend Payment.
  6. Each subclass implements processPayment() differently.
  7. Abstract-class references demonstrate runtime polymorphism.

Note: This example demonstrates object-oriented design only. A real payment system requires secure payment-provider integration, transaction validation, error handling, and suitable security controls.

16. Common Errors When Using Abstract Classes

Error Reason Solution
Creating an abstract-class object Abstract classes cannot be instantiated directly. Create an object of a concrete subclass.
Forgetting an abstract method A concrete subclass must implement all inherited abstract methods that remain unimplemented. Implement the methods or declare the subclass abstract.
Declaring an abstract method in a concrete class A class containing an abstract method must itself be abstract. Declare the class abstract or provide a method body.
Giving an abstract method a body Abstract methods declare behavior without providing an implementation. Remove the body or declare the method concrete.
Using an incompatible method signature The subclass method does not correctly override the inherited method. Use a compatible method signature and return type.
Declaring an abstract method as private A private method cannot be overridden by subclasses. Use an appropriate non-private access level.
Declaring an abstract method as static or final Static methods are not overridden polymorphically, and final methods cannot be overridden. Remove the conflicting modifier.

17. Common Mistakes and Corrections

Mistake 1: Instantiating an Abstract Class

abstract class Animal {
    abstract void makeSound();
}

// Invalid:
// Animal animal = new Animal();

Correction: Create an object of a concrete subclass.

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Cat meows");
    }
}

// Valid:
Animal animal = new Cat();
animal.makeSound();

Mistake 2: Not Implementing Required Methods

abstract class Shape {
    abstract void draw();
}

// Invalid if Circle is declared as a concrete class:
// class Circle extends Shape {
// }

Correction: Implement draw() in Circle, or declare Circle as abstract.

Mistake 3: Incorrect Method Signature

If the parent declares abstract void draw();, a subclass must provide a compatible implementation. A method with a different parameter list does not implement the original abstract method.

abstract class Shape {
    abstract void draw();
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

18. Best Practices for Abstract Classes

  • Use abstract classes when related classes share meaningful state or implementation.
  • Keep the parent class focused on common responsibilities.
  • Declare methods abstract when subclasses genuinely need different implementations.
  • Use meaningful class and method names, such as Payment, calculateArea(), and processPayment().
  • Use @Override when implementing or overriding inherited methods.
  • Choose appropriate access modifiers to protect internal state and expose intended behavior.
  • Initialize shared state through constructors when appropriate.
  • Prefer interfaces for capabilities that may be shared by unrelated classes.
  • Avoid unnecessarily deep inheritance hierarchies because they can make code harder to maintain.
  • Ensure that each concrete subclass fulfills the behavior promised by its abstract parent class.

19. Practice Exercises

Exercise 1: Animal Sounds

Create an abstract class named Animal with an abstract method makeSound(). Create Dog, Cat, and Cow subclasses with different implementations.

Exercise 2: Shape Calculator

Create an abstract class named Shape with abstract methods calculateArea() and calculatePerimeter(). Implement these methods in Circle and Rectangle.

Exercise 3: Employee Salary

Create an abstract class named Employee with fields for employee name and ID. Add an abstract method named calculateSalary() and implement it in full-time and part-time employee classes.

Exercise 4: Notification Service

Create an abstract class named Notification with a recipient field and an abstract method named sendNotification(). Implement email and SMS notification subclasses.

Exercise 5: Abstract Class and Polymorphism

Create an abstract class named Appliance with an abstract method named operate(). Create multiple subclasses and call their methods using an array of Appliance references.

20. Mini Project: Employee Management System

Project Objective: Build a simple employee management program using abstract classes, inheritance, constructors, method overriding, and runtime polymorphism.

Requirements

  • Create an abstract class named Employee.
  • Add fields for employee name and employee ID.
  • Create a constructor to initialize common employee details.
  • Add a concrete method named displayDetails().
  • Add an abstract method named calculateSalary().
  • Create concrete subclasses named FullTimeEmployee and PartTimeEmployee.
  • Implement salary calculations differently in each subclass.
  • Create objects and display employee details and calculated salaries.

Sample Implementation

abstract class Employee {
    String name;
    int employeeId;

    Employee(String name, int employeeId) {
        this.name = name;
        this.employeeId = employeeId;
    }

    void displayDetails() {
        System.out.println("Name: " + name);
        System.out.println("Employee ID: " + employeeId);
    }

    abstract double calculateSalary();
}

class FullTimeEmployee extends Employee {
    double monthlySalary;

    FullTimeEmployee(String name, int employeeId, double monthlySalary) {
        super(name, employeeId);
        this.monthlySalary = monthlySalary;
    }

    @Override
    double calculateSalary() {
        return monthlySalary;
    }
}

class PartTimeEmployee extends Employee {
    int hoursWorked;
    double hourlyRate;

    PartTimeEmployee(String name, int employeeId,
                     int hoursWorked, double hourlyRate) {
        super(name, employeeId);
        this.hoursWorked = hoursWorked;
        this.hourlyRate = hourlyRate;
    }

    @Override
    double calculateSalary() {
        return hoursWorked * hourlyRate;
    }
}

public class Main {
    public static void main(String[] args) {
        Employee employee1 =
            new FullTimeEmployee("Riya", 101, 40000);

        Employee employee2 =
            new PartTimeEmployee("Rahul", 102, 80, 250);

        employee1.displayDetails();
        System.out.println("Salary: " + employee1.calculateSalary());

        employee2.displayDetails();
        System.out.println("Salary: " + employee2.calculateSalary());
    }
}

Sample Output

Name: Riya
Employee ID: 101
Salary: 40000.0
Name: Rahul
Employee ID: 102
Salary: 20000.0

Learning Outcome: This project demonstrates how an abstract class can define shared employee information and a salary-calculation contract while allowing each employee type to calculate its salary differently.

21. Interview Questions and Answers

Q1. What is an abstract class in Java?

An abstract class is declared using the abstract keyword. It cannot be instantiated directly and can provide shared implementations and abstract methods for subclasses.

Q2. Can an abstract class contain concrete methods?

Yes. An abstract class can contain both abstract methods and concrete methods with implementations.

Q3. Can we create an object of an abstract class?

No. Direct instantiation is not allowed. However, a reference declared with an abstract class type can refer to an object of a concrete subclass.

Q4. Can an abstract class have a constructor?

Yes. Its constructor initializes inherited state when a subclass object is created.

Q5. Can an abstract class have no abstract methods?

Yes. A class can be abstract even when all its methods have implementations. This can prevent direct instantiation of a general-purpose parent class.

Q6. What happens if a subclass does not implement all abstract methods?

The subclass must also be abstract unless the required methods have already been implemented by an intermediate class.

Q7. Can an abstract class contain static methods?

Yes. Static methods can belong to an abstract class and can be called using the class name. Static methods are not overridden polymorphically like instance methods.

Q8. Can an abstract class extend another abstract class?

Yes. It can extend another abstract class and leave some abstract methods for a later concrete subclass to implement.

Q9. What is the difference between an abstract class and an interface?

An abstract class can maintain instance state, define constructors, and provide shared implementations. An interface primarily defines a contract or capability and allows a class to implement multiple interfaces.

Q10. Why is abstraction useful?

Abstraction separates the general definition of behavior from implementation details. It helps manage complexity and makes related classes easier to extend and maintain.

Q11. Can an abstract method be private?

No. A private method is not inherited for overriding, so an abstract method cannot be declared private.

Q12. Can an abstract method be final?

No. The final modifier prevents overriding, which conflicts with the purpose of an abstract method.

Q13. What is the role of @Override?

The annotation tells the compiler that a method is intended to override an inherited method. It helps identify incorrect signatures and other mistakes.

Q14. How do abstract classes support polymorphism?

A reference declared with an abstract parent type can refer to different concrete subclass objects. Overridden instance methods are selected according to the actual object's runtime type.

Q15. When should we choose an abstract class?

Choose an abstract class when related classes need shared implementation, common instance fields, constructor-based initialization, and behaviors that subclasses implement differently.

22. Quick Revision Notes

  • The abstract keyword declares an abstract class or method.
  • An abstract class cannot be instantiated directly.
  • An abstract method has no method body and ends with a semicolon.
  • A class that declares an abstract method must itself be abstract.
  • An abstract class can contain abstract and concrete methods.
  • Abstract classes can have constructors, fields, and static methods.
  • Subclasses inherit common functionality and implement required abstract methods.
  • A subclass with unimplemented abstract methods must remain abstract.
  • Abstract-class references can refer to concrete subclass objects.
  • Overridden instance methods support runtime polymorphism.
  • Abstract classes are useful for sharing common state and behavior among related classes.
  • Interfaces are useful for defining capabilities that can be shared across different class hierarchies.

23. Conclusion

Abstract classes are a fundamental feature of Java that help developers create reusable and maintainable object-oriented designs. They provide a common structure for related classes, allow shared code to be written once, and require subclasses to supply specific implementations where necessary.

By combining abstract methods, concrete methods, constructors, inheritance, and polymorphism, developers can design flexible applications such as payment systems, employee management tools, vehicle applications, and shape calculators.

Practise creating abstract classes, implementing subclasses, and using abstract-class references to invoke overridden methods to strengthen your understanding of this topic.

24. Additional Learning Resources

Previous Next
whatsapp